summaryrefslogtreecommitdiff
path: root/app/[lng]/evcp
diff options
context:
space:
mode:
authorjoonhoekim <26rote@gmail.com>2025-11-06 12:20:19 +0900
committerjoonhoekim <26rote@gmail.com>2025-11-06 12:20:19 +0900
commitec67f25270df089fa65315091afa24f0e8995b98 (patch)
tree8a0d0622b4efb4fef10d4c0bb676eef47c5fe8fc /app/[lng]/evcp
parentceaf46cd523f2bc94bbb35429e5ec0708a242caf (diff)
(김준회) 결재 후처리 강제실행 기능 추가
Diffstat (limited to 'app/[lng]/evcp')
-rw-r--r--app/[lng]/evcp/(evcp)/(system)/approval/log/[apInfId]/approval-log-detail-view.tsx68
1 files changed, 60 insertions, 8 deletions
diff --git a/app/[lng]/evcp/(evcp)/(system)/approval/log/[apInfId]/approval-log-detail-view.tsx b/app/[lng]/evcp/(evcp)/(system)/approval/log/[apInfId]/approval-log-detail-view.tsx
index 80cf4379..eb59fb28 100644
--- a/app/[lng]/evcp/(evcp)/(system)/approval/log/[apInfId]/approval-log-detail-view.tsx
+++ b/app/[lng]/evcp/(evcp)/(system)/approval/log/[apInfId]/approval-log-detail-view.tsx
@@ -3,9 +3,14 @@
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
import { Badge } from "@/components/ui/badge";
import { Separator } from "@/components/ui/separator";
+import { Button } from "@/components/ui/button";
import { ApprovalLogDetail } from "@/lib/approval-log/service";
import { formatDate } from "@/lib/utils";
-import { Clock, Mail, User, FileText, Shield, AlertCircle, CheckCircle, XCircle, Zap } from "lucide-react";
+import { Clock, Mail, User, FileText, Shield, AlertCircle, CheckCircle, XCircle, Zap, PlayCircle } from "lucide-react";
+import { forcePostProcessApproval } from "@/lib/approval-log/actions";
+import { toast } from "sonner";
+import { useRouter } from "next/navigation";
+import { useState } from "react";
interface ApprovalLogDetailViewProps {
detail: ApprovalLogDetail;
@@ -13,6 +18,38 @@ interface ApprovalLogDetailViewProps {
export function ApprovalLogDetailView({ detail }: ApprovalLogDetailViewProps) {
const { approvalLog, pendingAction } = detail;
+ const router = useRouter();
+ const [isProcessing, setIsProcessing] = useState(false);
+
+ // pendingAction이 있으면 후처리 버튼 표시 (서버에서 검증)
+ const canPostProcess = !!pendingAction;
+
+ const handlePostProcess = async () => {
+ if (isProcessing) return;
+
+ setIsProcessing(true);
+ try {
+ const result = await forcePostProcessApproval(approvalLog.apInfId);
+
+ if (result.success) {
+ toast.success('후처리 성공', {
+ description: result.message,
+ });
+ // 페이지 새로고침
+ router.refresh();
+ } else {
+ toast.error('후처리 실패', {
+ description: result.error,
+ });
+ }
+ } catch (error) {
+ toast.error('후처리 오류', {
+ description: error instanceof Error ? error.message : '알 수 없는 오류가 발생했습니다.',
+ });
+ } finally {
+ setIsProcessing(false);
+ }
+ };
// 상태 텍스트 변환
const getStatusText = (status: string) => {
@@ -252,13 +289,28 @@ export function ApprovalLogDetailView({ detail }: ApprovalLogDetailViewProps) {
{pendingAction && (
<Card>
<CardHeader>
- <CardTitle className="flex items-center gap-2">
- <CheckCircle className="h-5 w-5" />
- 액션 정보
- </CardTitle>
- <CardDescription>
- 결재와 연결된 Pending Action 정보입니다.
- </CardDescription>
+ <div className="flex items-center justify-between">
+ <div>
+ <CardTitle className="flex items-center gap-2">
+ <CheckCircle className="h-5 w-5" />
+ 액션 정보
+ </CardTitle>
+ <CardDescription>
+ 결재와 연결된 Pending Action 정보입니다.
+ </CardDescription>
+ </div>
+ {canPostProcess && (
+ <Button
+ onClick={handlePostProcess}
+ disabled={isProcessing || pendingAction.status === 'executed'}
+ size="sm"
+ variant={pendingAction.status === 'executed' ? 'outline' : 'default'}
+ >
+ <PlayCircle className="mr-2 h-4 w-4" />
+ {isProcessing ? '처리중...' : pendingAction.status === 'executed' ? '후처리 완료됨' : '후처리 실행'}
+ </Button>
+ )}
+ </div>
</CardHeader>
<CardContent className="space-y-4">
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">